package com.derbysoft.lowcostadapter.dswitch2.service.impl;

import com.derbysoft.lowcostadapter.commons.exception.SystemException;
import com.derbysoft.lowcostadapter.commons.log.PerformanceLogger;
import com.derbysoft.lowcostadapter.commons.model.RoomOccupancy;
import com.derbysoft.lowcostadapter.commons.model.SystemVariable;
import com.derbysoft.lowcostadapter.commons.redis.service.OccupancyCacheService;
import com.derbysoft.lowcostadapter.commons.redis.service.SystemVariableCacheService;
import com.derbysoft.lowcostadapter.commons.redis.utils.KeyValueHelper;
import com.derbysoft.lowcostadapter.commons.repository.SystemVariableRepository;
import com.derbysoft.lowcostadapter.commons.utils.DateTimeUtils;
import com.derbysoft.lowcostadapter.dswitch2.service.RoomOccupancyService;
import com.derbysoft.lowcostadapter.dswitch2.service.helper.Constant;
import com.derbysoft.lowcostadapter.schedule.parse.ParseRoomOccupancyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by: jason
 * Date: 2012-09-05
 */
@Service("roomOccupancyService")
public class RoomOccupancyServiceImpl implements RoomOccupancyService {

    @Autowired
    private OccupancyCacheService occupancyCacheService;

    @Autowired
    private ParseRoomOccupancyService parseRoomOccupancyService;

    @Autowired
    private SystemVariableRepository systemVariableRepository;

    @Autowired
    private SystemVariableCacheService systemVariableCacheService;

    @Override
    public boolean isRestricted(int propertyId, int adults, int children, StayDateRange stayDateRange) {
        return parseRoomOccupancyService.isParsing() || notFoundOccupancy(propertyId, adults, children, stayDateRange);
    }

    private boolean notFoundOccupancy(int propertyId, int adults, int children, StayDateRange stayDateRange) {
        String key = RoomOccupancy.PREFIX + KeyValueHelper.SEPARATOR + propertyId;
        List<RoomOccupancy> roomOccupancies = occupancyCacheService.loadAll(key);
        List<RoomOccupancy> availOccupancies = filterByDateRange(roomOccupancies, stayDateRange);
        List<RoomOccupancy> filteredRoomOccupancies = filterByOccupancy(availOccupancies, adults, children);

        String start = DateTimeUtils.formatDate(stayDateRange.getStart());
        String end = DateTimeUtils.formatDate(stayDateRange.getEnd());
        String field = start + "|" + end + "-" + adults + "-" + children;
        boolean searchNotFound = CollectionUtils.isEmpty(roomOccupancies);
        boolean restricted = CollectionUtils.isEmpty(filteredRoomOccupancies);
        PerformanceLogger.append("occupancy", String.format("%d:%s:%s:%s", propertyId, field, searchNotFound ? "Y" : "N", restricted ? "Y" : "N"));
        return restricted;
    }

    private List<RoomOccupancy> filterByDateRange(List<RoomOccupancy> roomOccupancies, StayDateRange stayDateRange) {
        List<RoomOccupancy> availOccupancies = new ArrayList<RoomOccupancy>();
        for (RoomOccupancy roomOccupancy : roomOccupancies) {
            Date start = DateTimeUtils.parse(roomOccupancy.getStart());
            Date end = DateTimeUtils.parse(roomOccupancy.getEnd());
            if (stayDateRange.getStart().compareTo(start) >= 0 && stayDateRange.getEnd().compareTo(end) <= 0) {
                availOccupancies.add(roomOccupancy);
            }
        }
        return availOccupancies;
    }

    private List<RoomOccupancy> filterByOccupancy(List<RoomOccupancy> roomOccupancies, int adults, int children) {
        List<RoomOccupancy> filteredRoomOccupancies = new ArrayList<RoomOccupancy>();
        for (RoomOccupancy roomOccupancy : roomOccupancies) {
            if (checkOccupancy(adults, children, roomOccupancy)) {
                continue;
            }
            filteredRoomOccupancies.add(roomOccupancy);
        }
        return filteredRoomOccupancies;
    }

    private boolean checkOccupancy(int adults, int children, RoomOccupancy roomOccupancy) {
        if (Boolean.valueOf(loadSystemVariable(Constant.OCCUPANCY_CHECK_STRICT).getValue())) {
            return roomOccupancy.getMaxAdults() < adults
                    || roomOccupancy.getMaxChildren() < children
                    || roomOccupancy.getMinAdults() > adults
                    || roomOccupancy.getMaxOccupancy() < adults + children
                    || (children > 0 && adults > roomOccupancy.getMaxAdultsWithChildren())
                    || roomOccupancy.getMinOccupancy() > adults + children;
        }
        return roomOccupancy.getMaxAdults() < adults
                || roomOccupancy.getMaxChildren() < children
                || roomOccupancy.getMinAdults() > adults;
    }

    protected SystemVariable loadSystemVariable(String name) {
        SystemVariable systemVariable = systemVariableCacheService.loadByName(name);
        if (systemVariable == null) {
            systemVariable = systemVariableRepository.findByName(name);
        }
        if (systemVariable == null) {
            throw new SystemException(String.format("system config not found:[%s] !!", name));
        }
        return systemVariable;
    }

    public void setOccupancyCacheService(OccupancyCacheService occupancyCacheService) {
        this.occupancyCacheService = occupancyCacheService;
    }

    public void setSystemVariableRepository(SystemVariableRepository systemVariableRepository) {
        this.systemVariableRepository = systemVariableRepository;
    }

    public void setSystemVariableCacheService(SystemVariableCacheService systemVariableCacheService) {
        this.systemVariableCacheService = systemVariableCacheService;
    }

    public void setParseRoomOccupancyService(ParseRoomOccupancyService parseRoomOccupancyService) {
        this.parseRoomOccupancyService = parseRoomOccupancyService;
    }
}
